home *** CD-ROM | disk | FTP | other *** search
- /* scrollbar implementation -- X interface.
- Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
- Copyright (C) 1994 Amdhal Corporation.
- Copyright (C) 1995 Sun Microsystems.
- Copyright (C) 1995 Darrell Kindred <dkindred+@cmu.edu>.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* Synched up with: Not in FSF. */
-
- #include <config.h>
- #include "lisp.h"
-
- #include "frame.h"
- #include "device-x.h"
- #include "frame-x.h"
- #include "glyphs-x.h" /* for kludge in Fx_set_scrollbar_pointer */
- #include "EmacsFrame.h"
- #include "EmacsManager.h"
- #include "lwlib.h"
- #include "scrollbar-x.h"
- #include "window.h"
-
- static void x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id,
- XtPointer client_data);
- static void x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id,
- XtPointer client_data);
-
- /* Used to prevent changing the size of the thumb while drag
- scrolling, under Motif. This is necessary because the Motif
- scrollbar is incredibly stupid about updating the thumb and causes
- lots of flicker if it is done too often. */
- static int inhibit_thumb_size_change;
-
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- static int vertical_drag_in_progress;
- #endif
-
-
- /* A device method. */
- static int
- x_inhibit_scrollbar_thumb_size_change (void)
- {
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- return inhibit_thumb_size_change;
- #else
- return 0;
- #endif
- }
-
- /* A device method. */
- static void
- x_free_scrollbar_instance (struct scrollbar_instance *instance)
- {
- if (SCROLLBAR_X_NAME (instance))
- xfree (SCROLLBAR_X_NAME (instance));
-
- if (SCROLLBAR_X_WIDGET (instance))
- {
- if (XtIsManaged (SCROLLBAR_X_WIDGET (instance)))
- XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
-
- lw_destroy_all_widgets (SCROLLBAR_X_ID (instance));
- }
- }
-
- /* A device method. */
- static void
- x_release_scrollbar_instance (struct scrollbar_instance *instance)
- {
- if (XtIsManaged (SCROLLBAR_X_WIDGET (instance)))
- XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
- }
-
- /* Defined in menubar-x.c */
- extern LWLIB_ID new_lwlib_id (void);
-
- /* A device method. */
- static void
- x_create_scrollbar_instance (struct frame *f, int vertical,
- struct scrollbar_instance *instance)
- {
- char buffer[32];
-
- /* initialize the X specific data section. */
- instance->scrollbar_data = malloc_type_and_zero (struct x_scrollbar_data);
-
- SCROLLBAR_X_ID (instance) = new_lwlib_id ();
- sprintf (buffer, "scrollbar_%d", SCROLLBAR_X_ID (instance));
- SCROLLBAR_X_NAME (instance) = xstrdup (buffer);
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = -1;
- #endif
-
- if (vertical)
- {
- SCROLLBAR_X_WIDGET (instance) =
- lw_create_widget ("vertical-scrollbar", SCROLLBAR_X_NAME (instance),
- SCROLLBAR_X_ID (instance),
- NULL, FRAME_X_CONTAINER_WIDGET (f), 0,
- x_update_vertical_scrollbar_callback, NULL, NULL);
- }
- else
- {
- SCROLLBAR_X_WIDGET (instance) =
- lw_create_widget ("horizontal-scrollbar", SCROLLBAR_X_NAME (instance),
- SCROLLBAR_X_ID (instance),
- NULL, FRAME_X_CONTAINER_WIDGET (f), 0,
- x_update_horizontal_scrollbar_callback, NULL, NULL);
- }
- }
-
- #define UPDATE_DATA_FIELD(field) \
- if (new_##field >= 0 && \
- SCROLLBAR_X_POS_DATA (inst).field != new_##field) { \
- SCROLLBAR_X_POS_DATA (inst).field = new_##field; \
- inst->scrollbar_instance_changed = 1; \
- }
-
- /* A device method. */
- /* #### The -1 check is such a hack. */
- static void
- x_update_scrollbar_instance_values (struct window *w,
- struct scrollbar_instance *inst,
- int new_line_increment,
- int new_page_increment,
- int new_minimum, int new_maximum,
- int new_slider_size,
- int new_slider_position,
- int new_scrollbar_width,
- int new_scrollbar_height,
- int new_scrollbar_x, int new_scrollbar_y)
- {
- UPDATE_DATA_FIELD (line_increment);
- UPDATE_DATA_FIELD (page_increment);
- UPDATE_DATA_FIELD (minimum);
- UPDATE_DATA_FIELD (maximum);
- UPDATE_DATA_FIELD (slider_size);
- UPDATE_DATA_FIELD (slider_position);
- UPDATE_DATA_FIELD (scrollbar_width);
- UPDATE_DATA_FIELD (scrollbar_height);
- UPDATE_DATA_FIELD (scrollbar_x);
- UPDATE_DATA_FIELD (scrollbar_y);
-
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- if (w && !vertical_drag_in_progress)
- {
- int new_vov = SCROLLBAR_X_POS_DATA (inst).slider_position;
- int new_vows = marker_position (w->start[CURRENT_DISP]);
-
- if (SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) != new_vov)
- {
- SCROLLBAR_X_VDRAG_ORIG_VALUE (inst) = new_vov;
- inst->scrollbar_instance_changed = 1;
- }
- if (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) != new_vows)
- {
- SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (inst) = new_vows;
- inst->scrollbar_instance_changed = 1;
- }
- }
- #endif
- }
-
- /* Used by x_update_scrollbar_instance_status. */
- static void
- update_one_scrollbar_bs (struct frame *f, Widget sb_widget)
- {
- Boolean use_backing_store;
-
- XtVaGetValues (FRAME_X_TEXT_WIDGET (f),
- XtNuseBackingStore, &use_backing_store, 0);
-
- if (use_backing_store && sb_widget)
- {
- unsigned long mask = CWBackingStore;
- XSetWindowAttributes attrs;
-
- attrs.backing_store = Always;
- XChangeWindowAttributes (XtDisplay (sb_widget),
- XtWindow (sb_widget),
- mask,
- &attrs);
- }
- }
-
- /* Create a widget value structure for passing down to lwlib so that
- it can update the scrollbar widgets. Used by
- x_update_scrollbar_instance_status. */
- static widget_value *
- scrollbar_instance_to_widget_value (struct scrollbar_instance *instance)
- {
- widget_value *wv;
-
- wv = xmalloc_widget_value ();
- /* #### maybe should add malloc_scrollbar_values to resource these? */
- wv->scrollbar_data = (scrollbar_values *)
- xmalloc (sizeof (scrollbar_values));
-
- wv->name = SCROLLBAR_X_NAME (instance);
- wv->value = 0;
- wv->key = 0;
- wv->enabled = instance->scrollbar_is_active;
- wv->selected = 0;
- wv->call_data = NULL;
-
- *wv->scrollbar_data = SCROLLBAR_X_POS_DATA (instance);
-
- wv->next = NULL;
-
- return wv;
- }
-
- /* Used by x_update_scrollbar_instance_status. */
- static void
- update_one_widget_scrollbar_pointer (struct frame *f, Widget wid)
- {
- Lisp_Object cursor = f->scrollbar_pointer;
-
- if (CURSORP (cursor)) /* #### kludge */
- {
- XDefineCursor (XtDisplay (wid), XtWindow (wid),
- XCURSOR (cursor)->cursor);
- XSync (XtDisplay (wid), False);
- }
- }
-
- /* A device method. */
- static void
- x_update_scrollbar_instance_status (struct window *w, int active, int size,
- struct scrollbar_instance *instance)
- {
- struct frame *f = XFRAME (w->frame);
- char managed = XtIsManaged (SCROLLBAR_X_WIDGET (instance));
-
- if (active && size)
- {
- widget_value *wv = scrollbar_instance_to_widget_value (instance);
-
- if (instance->scrollbar_instance_changed)
- {
- lw_modify_all_widgets (SCROLLBAR_X_ID (instance), wv, 0);
- instance->scrollbar_instance_changed = 0;
- }
-
- if (!managed)
- {
- XtManageChild (SCROLLBAR_X_WIDGET (instance));
- if (XtWindow (SCROLLBAR_X_WIDGET (instance)))
- {
- /* Raise this window so that it's visible on top of the
- text window below it. */
- XRaiseWindow (XtDisplay (SCROLLBAR_X_WIDGET (instance)),
- XtWindow (SCROLLBAR_X_WIDGET (instance)));
- update_one_widget_scrollbar_pointer (f,
- SCROLLBAR_X_WIDGET (instance));
- if (!SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance))
- {
- update_one_scrollbar_bs (f, SCROLLBAR_X_WIDGET (instance));
- SCROLLBAR_X_BACKING_STORE_INITIALIZED (instance) = 1;
- }
- }
- }
-
- if (!wv->scrollbar_data) abort ();
- xfree (wv->scrollbar_data);
- wv->scrollbar_data = 0;
- free_widget_value (wv);
- }
- else if (managed)
- {
- XtUnmanageChild (SCROLLBAR_X_WIDGET (instance));
- }
- }
-
- /* A device method. */
- static void
- x_scrollbar_width_changed_in_frame (Lisp_Object specifier, struct frame *f,
- Lisp_Object oldval)
- {
- XtWidgetGeometry req, repl;
- Lisp_Object newval = f->scrollbar_width;
-
- in_specifier_change_function++;
-
- /* We want the text area to stay the same size. So, we query the
- current size and then adjust it for the change in the scrollbar
- width. */
-
- /* mirror the value in the frame resources, unless it was already
- done. */
- if (!in_resource_setting)
- XtVaSetValues (FRAME_X_TEXT_WIDGET (f), XtNscrollBarWidth,
- XINT (newval), 0);
-
- if (XtIsRealized (FRAME_X_CONTAINER_WIDGET (f)))
- {
- req.request_mode = 0;
-
- /* the query-geometry method looks at the current value of
- f->scrollbar_width, so temporarily set it back to the old
- one. */
- f->scrollbar_width = oldval;
- XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
- f->scrollbar_width = newval;
-
- repl.width += XINT (newval) - XINT (oldval);
- EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
- repl.height);
- }
-
- in_specifier_change_function--;
- }
-
- /* A device method. */
- static void
- x_scrollbar_height_changed_in_frame (Lisp_Object specifier, struct frame *f,
- Lisp_Object oldval)
- {
- XtWidgetGeometry req, repl;
- Lisp_Object newval = f->scrollbar_height;
-
- in_specifier_change_function++;
-
- /* We want the text area to stay the same size. So, we query the
- current size and then adjust it for the change in the scrollbar
- height. */
-
- /* mirror the value in the frame resources, unless it was already
- done. Also don't do it if this is the when the frame is being
- created -- the widgets don't even exist yet, and even if they
- did, we wouldn't want to overwrite the resource information
- (which might specify a user preference). */
- if (!in_resource_setting)
- XtVaSetValues (FRAME_X_TEXT_WIDGET (f), XtNscrollBarHeight,
- XINT (newval), 0);
-
- if (XtIsRealized (FRAME_X_CONTAINER_WIDGET (f)))
- {
- req.request_mode = 0;
-
- /* the query-geometry method looks at the current value of
- f->scrollbar_height, so temporarily set it back to the old
- one. */
- f->scrollbar_height = oldval;
- XtQueryGeometry (FRAME_X_CONTAINER_WIDGET (f), &req, &repl);
- f->scrollbar_height = newval;
-
- repl.height += XINT (newval) - XINT (oldval);
- EmacsManagerChangeSize (FRAME_X_CONTAINER_WIDGET (f), repl.width,
- repl.height);
- }
-
- in_specifier_change_function--;
- }
-
- enum x_scrollbar_loop
- {
- X_FIND_SCROLLBAR_WINDOW_MIRROR,
- X_SET_SCROLLBAR_POINTER,
- X_WINDOW_IS_SCROLLBAR,
- X_UPDATE_FRAME_SCROLLBARS
- };
-
- static struct window_mirror *
- x_scrollbar_loop (enum x_scrollbar_loop type, Lisp_Object window,
- struct window_mirror *mir,
- LWLIB_ID id, Window x_win)
- {
- struct window_mirror *retval = NULL;
-
- while (mir)
- {
- struct scrollbar_instance *vinstance = mir->scrollbar_vertical_instance;
- struct scrollbar_instance *hinstance =
- mir->scrollbar_horizontal_instance;
- struct frame *f;
-
- assert (!NILP (window));
- f = XFRAME (XWINDOW (window)->frame);
-
- if (mir->vchild)
- {
- retval = x_scrollbar_loop (type, XWINDOW (window)->vchild,
- mir->vchild, id, x_win);
- }
- else if (mir->hchild)
- {
- retval = x_scrollbar_loop (type, XWINDOW (window)->hchild,
- mir->hchild, id, x_win);
- }
-
- if (retval != NULL)
- return retval;
-
- if (hinstance || vinstance)
- {
- switch (type)
- {
- case X_FIND_SCROLLBAR_WINDOW_MIRROR:
- if ((vinstance && SCROLLBAR_X_ID (vinstance) == id)
- || (hinstance && SCROLLBAR_X_ID (hinstance) == id))
- {
- return mir;
- }
- break;
- case X_UPDATE_FRAME_SCROLLBARS:
- if (!mir->vchild && !mir->hchild)
- update_window_scrollbars (XWINDOW (window), mir, 1, 0);
- break;
- case X_SET_SCROLLBAR_POINTER:
- if (!mir->vchild && !mir->hchild)
- {
- int loop;
-
- for (loop = 0; loop < 2; loop++)
- {
- Widget widget;
-
- if (loop)
- widget = SCROLLBAR_X_WIDGET (vinstance);
- else
- widget = SCROLLBAR_X_WIDGET (hinstance);
-
- if (widget && XtIsManaged (widget))
- {
- update_one_widget_scrollbar_pointer (f, widget);
- }
- }
- }
- break;
- case X_WINDOW_IS_SCROLLBAR:
- if (!mir->vchild && !mir->hchild)
- {
- int loop;
-
- for (loop = 0; loop < 2; loop++)
- {
- Widget widget;
-
- if (loop)
- widget = SCROLLBAR_X_WIDGET (vinstance);
- else
- widget = SCROLLBAR_X_WIDGET (hinstance);
-
- if (widget && XtIsManaged (widget))
- {
- if (XtWindow (widget) == x_win)
- return (struct window_mirror *) 1;
- }
- }
- }
- break;
- default:
- abort ();
- }
- }
-
- mir = mir->next;
- window = XWINDOW (window)->next;
- }
-
- return NULL;
- }
-
- /* Used by callbacks. */
- static struct window_mirror *
- find_scrollbar_window_mirror (struct frame *f, LWLIB_ID id)
- {
- if (f->mirror_dirty)
- update_frame_window_mirror (f);
- return x_scrollbar_loop (X_FIND_SCROLLBAR_WINDOW_MIRROR, f->root_window,
- f->root_mirror, id, (Window) NULL);
- }
-
- /*
- * This is the only callback provided for vertical scrollbars. It
- * should be able to handle all of the scrollbar events in
- * scroll_action (see lwlib.h). The client data will be of type
- * scroll_event (see lwlib.h). */
- static void
- x_update_vertical_scrollbar_callback (Widget widget, LWLIB_ID id,
- XtPointer client_data)
- {
- /* This function can GC */
- scroll_event *data = (scroll_event *) client_data;
- struct device *d = get_device_from_display (XtDisplay (widget));
- struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
- Lisp_Object win;
- struct scrollbar_instance *instance;
- struct window_mirror *mirror;
-
- if (!f)
- return;
-
- mirror = find_scrollbar_window_mirror (f, id);
- win = real_window (mirror, 1);
-
- if (NILP (win))
- return;
- instance = mirror->scrollbar_vertical_instance;
-
- /* It seems that this is necessary whenever signal_special_Xt_user_event()
- is called. #### Why??? */
- DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
-
- switch (data->action)
- {
- case SCROLLBAR_LINE_UP:
- signal_special_Xt_user_event (Qscrollbar_line_up, win);
- break;
-
- case SCROLLBAR_LINE_DOWN:
- signal_special_Xt_user_event (Qscrollbar_line_down, win);
- break;
-
- /* The Athena scrollbar paging behavior is that of xterms.
- Depending on where you click the size of the page varies.
- Motif always does a standard Emacs page. */
- case SCROLLBAR_PAGE_UP:
- #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID)
- {
- double tmp = ((double) data->slider_value /
- (double) instance->data.scrollbar_height);
- double line = tmp *
- (double) window_displayed_height (XWINDOW (win));
-
- if (line > -1.0)
- line = -1.0;
- signal_special_Xt_user_event (Qscrollbar_page_up,
- Fcons (win, make_number ((int) line)));
- }
- #else
- signal_special_Xt_user_event (Qscrollbar_page_up, Fcons (win, Qnil));
- #endif
- break;
-
- case SCROLLBAR_PAGE_DOWN:
- #if !defined (LWLIB_SCROLLBARS_MOTIF) && !defined (LWLIB_SCROLLBARS_LUCID)
- {
- double tmp = ((double) data->slider_value /
- (double) instance->data.scrollbar_height);
- double line = tmp *
- (double) window_displayed_height (XWINDOW (win));
-
- if (instance->data.maximum >
- (instance->data.slider_size + instance->data.slider_position))
- {
- if (line < 1.0)
- line = 1.0;
- signal_special_Xt_user_event (Qscrollbar_page_down,
- Fcons (win,
- make_number ((int) line)));
- }
- }
- #else
- signal_special_Xt_user_event (Qscrollbar_page_down, Fcons (win, Qnil));
- #endif
- break;
-
- case SCROLLBAR_TOP:
- signal_special_Xt_user_event (Qscrollbar_to_top, win);
- break;
-
- case SCROLLBAR_BOTTOM:
- signal_special_Xt_user_event (Qscrollbar_to_bottom, win);
- break;
-
-
- case SCROLLBAR_CHANGE:
- inhibit_thumb_size_change = 0;
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- vertical_drag_in_progress = 0;
- SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value;
- SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) =
- XINT (Fwindow_start (win));
- #endif
- break;
-
- case SCROLLBAR_DRAG:
- {
- int value;
-
- inhibit_thumb_size_change = 1;
-
- #if defined (LWLIB_SCROLLBARS_MOTIF) || defined (LWLIB_SCROLLBARS_LUCID)
- /* Doing drags with Motif-like scrollbars is a mess, since we
- want to avoid having the window position jump when you
- first grab the scrollbar, but we also want to ensure that
- you can scroll all the way to the top or bottom of the
- buffer. This can all be replaced with something sane when
- we get line-based scrolling. */
-
- vertical_drag_in_progress = 1;
-
- if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) < 0)
- {
- SCROLLBAR_X_VDRAG_ORIG_VALUE (instance) = data->slider_value;
- SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance) =
- XINT (Fwindow_start (win));
- }
-
- /* Could replace this piecewise linear scrolling with a
- quadratic through the three points, but I'm not sure that
- would feel any nicer in practice. */
- if (data->slider_value < SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))
- {
- /* We've dragged up; slide linearly from original position to
- window-start=data.minimum, slider-value=data.minimum. */
-
- if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
- <= SCROLLBAR_X_POS_DATA (instance).minimum)
- {
- /* shouldn't get here, but just in case */
- value = SCROLLBAR_X_POS_DATA (instance).minimum;
- }
- else
- {
- value = (SCROLLBAR_X_POS_DATA (instance).minimum
- + (((double) (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)
- - SCROLLBAR_X_POS_DATA (instance).minimum)
- * (data->slider_value -
- SCROLLBAR_X_POS_DATA (instance).minimum))
- / (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
- - SCROLLBAR_X_POS_DATA (instance).minimum)));
- }
- }
- else
- {
- /* We've dragged down; slide linearly from original position to
- window-start=data.maximum, slider-value=data.maximum. */
-
- if (SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)
- >= (SCROLLBAR_X_POS_DATA (instance).maximum -
- SCROLLBAR_X_POS_DATA (instance).slider_size))
- {
- /* avoid divide by zero */
- value = SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance);
- }
- else
- {
- value = (SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance)
- + (((double) (SCROLLBAR_X_POS_DATA (instance).maximum
- - SCROLLBAR_X_VDRAG_ORIG_WINDOW_START (instance))
- * (data->slider_value
- - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance)))
- / (SCROLLBAR_X_POS_DATA (instance).maximum
- - SCROLLBAR_X_POS_DATA (instance).slider_size
- - SCROLLBAR_X_VDRAG_ORIG_VALUE (instance))));
- }
- }
- #else
- value = data->slider_value;
- #endif
-
- if (value >= SCROLLBAR_X_POS_DATA (instance).maximum)
- value = SCROLLBAR_X_POS_DATA (instance).maximum - 1;
- if (value < SCROLLBAR_X_POS_DATA (instance).minimum)
- value = SCROLLBAR_X_POS_DATA (instance).minimum;
-
- signal_special_Xt_user_event (Qscrollbar_vertical_drag,
- Fcons (win, make_number (value)));
- }
- break;
-
- }
- }
-
- /*
- * This is the only callback provided for horizontal scrollbars. It
- * should be able to handle all of the scrollbar events in
- * scroll_action (see lwlib.h). The client data will be of type
- * scroll_event (see lwlib.h). */
- static void
- x_update_horizontal_scrollbar_callback (Widget widget, LWLIB_ID id,
- XtPointer client_data)
- {
- scroll_event *data = (scroll_event *) client_data;
- struct device *d = get_device_from_display (XtDisplay (widget));
- struct frame *f = x_any_window_to_frame (d, XtWindow (widget));
- Lisp_Object win;
- struct window_mirror *mirror;
-
- if (!f)
- return;
-
- mirror = find_scrollbar_window_mirror (f, id);
- win = real_window (mirror, 1);
-
- if (NILP (win))
- return;
-
- /* It seems that this is necessary whenever signal_special_Xt_user_event()
- is called. #### Why??? */
- DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
-
- switch (data->action)
- {
- case SCROLLBAR_LINE_UP:
- signal_special_Xt_user_event (Qscrollbar_char_left, win);
- break;
- case SCROLLBAR_LINE_DOWN:
- signal_special_Xt_user_event (Qscrollbar_char_right, win);
- break;
- case SCROLLBAR_PAGE_UP:
- signal_special_Xt_user_event (Qscrollbar_page_left, win);
- break;
- case SCROLLBAR_PAGE_DOWN:
- signal_special_Xt_user_event (Qscrollbar_page_right, win);
- break;
- case SCROLLBAR_TOP:
- signal_special_Xt_user_event (Qscrollbar_to_left, win);
- break;
- case SCROLLBAR_BOTTOM:
- signal_special_Xt_user_event (Qscrollbar_to_right, win);
- break;
- case SCROLLBAR_CHANGE:
- inhibit_thumb_size_change = 0;
- break;
- case SCROLLBAR_DRAG:
- inhibit_thumb_size_change = 1;
- /* #### Fix the damn toolkit code so they all work the same way.
- Lucid is the one mostly wrong.*/
- #if defined (LWLIB_SCROLLBARS_LUCID)
- signal_special_Xt_user_event (Qscrollbar_horizontal_drag,
- (Fcons
- (win, make_number (data->slider_value))));
- #else
- signal_special_Xt_user_event (Qscrollbar_horizontal_drag,
- (Fcons
- (win,
- make_number (data->slider_value - 1))));
- #endif
- break;
- default:
- break;
- }
- }
-
- /* Called directly by Fx_set_scrollbar_pointer in frame-x.c */
- void
- x_set_scrollbar_pointer (struct frame *f, Lisp_Object cursor)
- {
- if (!FRAME_IS_X (f))
- return;
-
- if (!EQ (f->scrollbar_pointer, cursor))
- {
- /* #### If the user cuts this pointer, we'll get X errors.
- This needs to be rethunk. */
- f->scrollbar_pointer = cursor;
-
- if (f->mirror_dirty)
- update_frame_window_mirror (f);
- x_scrollbar_loop (X_SET_SCROLLBAR_POINTER, f->root_window,
- f->root_mirror, 0, (Window) NULL);
- }
- }
-
- /* Called directly from x_any_window_to_frame in frame-x.c */
- int
- x_window_is_scrollbar (struct frame *f, Window win)
- {
- if (!FRAME_IS_X (f))
- return 0;
-
- if (f->mirror_dirty)
- update_frame_window_mirror (f);
- return (int) x_scrollbar_loop (X_WINDOW_IS_SCROLLBAR, f->root_window,
- f->root_mirror, 0, win);
- }
-
- /* Make sure that all scrollbars on frame are up-to-date. Called
- directly from x_set_frame_params_1 in frame-x.c*/
- void
- x_update_frame_scrollbars (struct frame *f)
- {
- /* Consider this code to be "in_display" so that we abort() if Fsignal()
- gets called. */
- in_display++;
- x_scrollbar_loop (X_UPDATE_FRAME_SCROLLBARS, f->root_window, f->root_mirror,
- 0, (Window) NULL);
- in_display--;
- if (in_display < 0) abort ();
- }
-
- /************************************************************************/
- /* initialization */
- /************************************************************************/
-
- void
- device_type_create_scrollbar_x (void)
- {
- DEVICE_HAS_METHOD (x, inhibit_scrollbar_thumb_size_change);
- DEVICE_HAS_METHOD (x, free_scrollbar_instance);
- DEVICE_HAS_METHOD (x, release_scrollbar_instance);
- DEVICE_HAS_METHOD (x, create_scrollbar_instance);
- DEVICE_HAS_METHOD (x, update_scrollbar_instance_values);
- DEVICE_HAS_METHOD (x, update_scrollbar_instance_status);
- DEVICE_HAS_METHOD (x, scrollbar_width_changed_in_frame);
- DEVICE_HAS_METHOD (x, scrollbar_height_changed_in_frame);
- }
-
- void
- vars_of_scrollbar_x (void)
- {
- #if defined (LWLIB_SCROLLBARS_LUCID)
- Fprovide (intern ("lucid-scrollbars"));
- #elif defined (LWLIB_SCROLLBARS_MOTIF)
- Fprovide (intern ("motif-scrollbars"));
- #elif defined (LWLIB_SCROLLBARS_ATHENA)
- Fprovide (intern ("athena-scrollbars"));
- #endif
- }
-